
#ifndef _XML_CONFIG_
#define _XML_CONFIG_

#include <string>
#include "tinystr.h"
#include "tinyxml.h"

#ifdef __Win32__
#define CONFIG_FILE_NAME  "./config/config.xml"
#else
#define CONFIG_FILE_NAME  "../config/config.xml"
#endif

#define GET_CONTENT_VALUE(strPos,value,isDynUpdate) \
        {\
            if(m_isFirstRead || isDynUpdate)\
            {\
                SConfig::m_mtxConfig.Lock();\
                if (!m_pDoc->GetContent(strPos,value))\
				{\
					std::string strPrint=strPos;\
                    printf("config not find [%s]\n",strPrint.c_str());\
                }\
                SConfig::m_mtxConfig.Unlock();\
            }\
        }\


#define GET_ATTRIBUTE_VALUE(strPos,value,isDynUpdate) \
        {\
            if(m_isFirstRead || isDynUpdate)\
            {\
                SConfig::m_mtxConfig.Lock();\
                if (!m_pDoc->GetAttribute(strPos,value))\
                {\
					std::string strPrint=strPos;\
                    printf("config not find [%s]\n",strPrint.c_str());\
                }\
                SConfig::m_mtxConfig.Unlock();\
            }\
        }\

//log
#define CONFIG_PARA_LOG_LEVEL	         "config/logpara/log_level"
#define CONFIG_PARA_LOG_SIZE	         "config/logpara/log_file_size"
#define CONFIG_PARA_LOG_NUM   	         "config/logpara/log_file_num"
#define CONFIG_PARA_LOG_PATH 	         "config/logpara/log_path"


#define CONFIG_LISTEN_ADDR_MGR          "config/manage/listen_addr_mgr"
#define CONFIG_LISTEN_ADDR_MGR_EXTERNAL     "config/manage/listen_addr_mgr_external"
#define CONFIG_HTTP_RECV_HANDLER_NUM    "config/manage/http_recv_handler_num"
#define CONFIG_HTTP_POST_HANDLER_NUM    "config/manage/http_post_handler_num"
#define CONFIG_HTTP_POST_MSG_MAX_QUEUE  "config/manage/http_post_max_msg_queue"
#define CONFIG_IS_SUPPORT_LONG_CONNECT  "config/manage/is_support_long_connect"

#define CONFIG_CPU_BIND_ENABLE	        "config/cpu_bind_info/cpu_bind_enable"
#define CONFIG_CPU_BIND_ADAPT_ENABLE	"config/cpu_bind_info/cpu_bind_adapt_enable"
#define CONFIG_CPU_BIND_NUM_LOW	        "config/cpu_bind_info/cpu_num_low"
#define CONFIG_CPU_BIND_NUM_MID	        "config/cpu_bind_info/cpu_num_mid"
#define CONFIG_CPU_BIND_NUM_HIGH        "config/cpu_bind_info/cpu_num_high"
#define CONFIG_CPU_BIND_NUM_MAX_HIGH    "config/cpu_bind_info/cpu_num_max_high"

#define CONFIG_DB_INFO_TYPE	             "config/db_info/db_type"
#define CONFIG_DB_INFO_SERVER	         "config/db_info/db_server"
#define CONFIG_DB_INFO_PORT  	         "config/db_info/db_port"
#define CONFIG_DB_INFO_DB_NAME	         "config/db_info/db_name"
#define CONFIG_DB_INFO_DB_USER	         "config/db_info/db_user"
#define CONFIG_DB_INFO_DB_PASSWD         "config/db_info/db_passwd"
#define CONFIG_DB_INFO_DB_CHARSET        "config/db_info/db_charset"
#define CONFIG_DB_INFO_DB_MAX_CONN	     "config/db_info/db_max_conn"

/*
#define LOAD_LISTEN_PARA(listen_cfg,default_addr)                   \
{                                                                   \
    std::string strListenAddr  = default_addr;                      \
                                                                    \
    GET_CONTENT_VALUE(listen_cfg,strListenAddr,FALSE);              \
                                                                    \
    SConfig::m_lstListenAddr.push_back(strListenAddr);              \
}
*/

#define LOAD_LISTEN_PARA(listen_cfg,default_addr)                   \
{                                                                   \
    for(int i=0; i<10; i++)\
    {\
        std::string strListenAddr;                                  \
        char tmpBuf[128] = {0};                                     \
        sprintf(tmpBuf, "%s&%d", listen_cfg, i);                    \
        std::string strTag = tmpBuf;                                \
        GET_CONTENT_VALUE(strTag,strListenAddr,FALSE);              \
        if (strListenAddr.empty())                                  \
        {\
            break;\
        }\
        else\
        {\
           SConfig::m_lstListenAddr.push_back(strListenAddr);       \
        }\
    }\
}    


#define LOAD_LOG_PARA()                                                                  \
{                                                                                        \
    GET_CONTENT_VALUE(CONFIG_PARA_LOG_LEVEL, SConfig::m_sLogPara.iLogLevel,     TRUE);   \
    GET_CONTENT_VALUE(CONFIG_PARA_LOG_SIZE,  SConfig::m_sLogPara.iLogFileSize,  FALSE);  \
    GET_CONTENT_VALUE(CONFIG_PARA_LOG_NUM,   SConfig::m_sLogPara.iLogFileCount, FALSE);  \
    GET_CONTENT_VALUE(CONFIG_PARA_LOG_PATH,  SConfig::m_sLogPara.strLogPath,    FALSE);  \
																						 \
    OS::CheckPathDelimiter(SConfig::m_sLogPara.strLogPath);                              \
    OS::replace_all(SConfig::m_sLogPara.strLogPath,"\\","/");                            \
}

#define LOAD_HANDLER_NUM()                                                                  \
{                                                                                           \
    GET_CONTENT_VALUE(CONFIG_HTTP_RECV_HANDLER_NUM,   SConfig::m_iRecvHandlerNum,    FALSE);\
    GET_CONTENT_VALUE(CONFIG_HTTP_POST_HANDLER_NUM,   SConfig::m_iHttpPostHandlerNum,FALSE);\
    GET_CONTENT_VALUE(CONFIG_HTTP_POST_MSG_MAX_QUEUE, SConfig::m_iMaxMsgQueue,       FALSE);\
    GET_CONTENT_VALUE(CONFIG_IS_SUPPORT_LONG_CONNECT, SConfig::m_isSupportLongConn,  FALSE);\
}

#define LOAD_DB_INFO()                                                                       \
{                                                                                             \
    GET_CONTENT_VALUE(CONFIG_DB_INFO_TYPE,       SConfig::m_sDBinfo.iDBtype,            FALSE);\
    GET_CONTENT_VALUE(CONFIG_DB_INFO_SERVER,     SConfig::m_sDBinfo.strMysqDBserver,    FALSE);\
    GET_CONTENT_VALUE(CONFIG_DB_INFO_DB_NAME,    SConfig::m_sDBinfo.strDBname,          FALSE);\
    GET_CONTENT_VALUE(CONFIG_DB_INFO_DB_USER,    SConfig::m_sDBinfo.strDBuser,   FALSE);\
    GET_CONTENT_VALUE(CONFIG_DB_INFO_DB_PASSWD,  SConfig::m_sDBinfo.strDBpasswd, FALSE);\
    GET_CONTENT_VALUE(CONFIG_DB_INFO_DB_CHARSET, SConfig::m_sDBinfo.strDBcharset,FALSE);\
    GET_CONTENT_VALUE(CONFIG_DB_INFO_DB_MAX_CONN,SConfig::m_sDBinfo.iDBmaxconn,  FALSE);\
                                                                                        \
    SConfig::m_sDBinfo.strOracleDBconnection = SConfig::m_sDBinfo.strMysqDBserver + "/" ;         \
    SConfig::m_sDBinfo.strOracleDBconnection += SConfig::m_sDBinfo.strDBname;                 \
}

// cpu bind adapt
//    1/16, 1/8, 1/3, 1/2
//32:    2    4   10   16
//24:    1    3    8   12
// 8:    1    1    3    3
#define LOAD_CPU_BIND_INFO()                                                                                    \
{                                                                                                               \
    BOOL isSupportCpuBind = FALSE;                                                                              \
    GET_CONTENT_VALUE(CONFIG_CPU_BIND_ENABLE,  isSupportCpuBind,	 FALSE);                                    \
    if (!isSupportCpuBind)                                                                                      \
    {                                                                                                           \
        return TRUE;                                                                                            \
    }                                                                                                           \
                                                                                                                \
    SInt32 iCpuTotal     =  0;                                                                                  \
    SInt32 iLowCount     = -1;                                                                                  \
    SInt32 iMidCount     = -1;                                                                                  \
    SInt32 iHighCount    = -1;                                                                                  \
    SInt32 iMaxHighCount = -1;                                                                                  \
                                                                                                                \
    BOOL isSupportCpuBindAdapt = FALSE;                                                                         \
    GET_CONTENT_VALUE(CONFIG_CPU_BIND_ADAPT_ENABLE,  isSupportCpuBindAdapt,	 FALSE);                            \
    if (isSupportCpuBindAdapt)                                                                                  \
    {                                                                                                           \
        iCpuTotal = CCpuBind::GetSingletonPtr()->GetCpuAdapterNum(iLowCount,iMidCount,iHighCount,iMaxHighCount);\
    }                                                                                                           \
    else                                                                                                        \
    {                                                                                                           \
        GET_CONTENT_VALUE(CONFIG_CPU_BIND_NUM_LOW,        iLowCount,     FALSE);                                \
        GET_CONTENT_VALUE(CONFIG_CPU_BIND_NUM_MID,        iMidCount,     FALSE);                                \
        GET_CONTENT_VALUE(CONFIG_CPU_BIND_NUM_HIGH,	      iHighCount,    FALSE);                                \
        GET_CONTENT_VALUE(CONFIG_CPU_BIND_NUM_MAX_HIGH,	  iMaxHighCount, FALSE);                                \
                                                                                                                \
        iCpuTotal = CCpuBind::GetSingletonPtr()->GetCpuCoreNum();                                               \
        if (iCpuTotal < (iLowCount+iMidCount+iHighCount+iMaxHighCount))                                         \
        {                                                                                                       \
            char szTmp1[256] = "";                                                                              \
            sprintf(szTmp1,"cpu num not enough,cpu bind cfg error! iCpuTotal = %d, iLowCount = %d, iMidCount = %d, iHighCount = %d, iMaxHighCount = %d",iCpuTotal,iLowCount,iMidCount,iHighCount,iMaxHighCount);\
            printf("\n%s\n",szTmp1);                                                                            \
            LOG_ERROR(szTmp1);                                                                                  \
            return FALSE;                                                                                       \
        }                                                                                                       \
    }                                                                                                           \
                                                                                                                \
    char szTmp2[256] = "";                                                                                      \
    CCpuBind::GetSingletonPtr()->InitBindPara(iLowCount,iMidCount,iHighCount,iMaxHighCount);                    \
    sprintf(szTmp2,"cpu bind para, iCpuTotal = %d, iLowCount = %d, iMidCount = %d, iHighCount = %d, iMaxHighCount = %d",iCpuTotal,iLowCount,iMidCount,iHighCount,iMaxHighCount);\
    printf("\n%s\n",szTmp2);                                                                                    \
    LOG_INFO(szTmp2);                                                                                           \
}


class CSrvConfig
{
public:
    CSrvConfig();
    virtual ~CSrvConfig();

    virtual void Init(const std::string& strFileName = "");
    virtual bool IsModify();
    virtual bool LoadConfig();

    virtual bool InitCfgXml();
    virtual void LoadLogPara() = 0;

protected:
    virtual bool LoadMyItems()=0;

protected:
    std::string    m_strFileName;
    time_t         m_tLastModeTime;
    TiXmlDocument* m_pDoc;

    bool           m_isFirstRead;
};

#endif

